package com.lagou.subjecttwo;

/**
 * 五子棋类
 */

public class Gobang {
    /**
     * 声明棋盘
     */
    private String[][] GoBangCheckerBoard;
    /**
     * 棋盘输出对照表 map匹配 后面的字符
     */
    private String[] map = {"", "a", "b", "c", "d", "e", "f"};
    /**
     * 判断下一手是否是黑子执棋
     */
    private boolean nextBlack = true;

    /**
     * 定义白棋子
     */
    private final String WhiteChess = "○";
    /**
     * 定义黑棋子
     */
    private final String BlackChess = "●";

    /**
     * 棋盘上，黑棋的个数
     */
    private int BlackCount = 0;
    /**
     * 棋盘上，白棋的个数
     */
    private int WhiteCount = 0;
    /**
     * 棋盘可以下的总数量
     */
    private int TotalCount = 256;

    public Gobang() {
        //创建先初始化棋盘
        IndiGoBangCheckerBoard();
        //初始化完成查看下
        ShowGoBangCheckerBoard();
    }

    /**
     * 初始化棋盘
     */
    public void IndiGoBangCheckerBoard() {
        //重新初始化，直接使用模块一的作业代码
        GoBangCheckerBoard = new String[17][17];
        //双重循环 赋值
        for (int i = 0; i < 17; i++) {
            for (int j = 0; j < 17; j++) {
                //第一个空直接为空
                if (i == 0 && j == 0) {
                    GoBangCheckerBoard[i][j] = " ";
                } else if (i == 0 || j == 0) {
                    //横向第一排和竖向第一排 需要单独处理
                    //大于10 和 小于 10 要单独处理。
                    if ((i == 0 && j <= 10) || (j == 0 && i <= 10)) {
                        GoBangCheckerBoard[i][j] = i == 0 ? j - 1 + "" : i - 1 + "";
                    } else {
                        GoBangCheckerBoard[i][j] = i == 0 ? map[j % 10] : map[i % 10];
                    }
                } else
                    GoBangCheckerBoard[i][j] = "+";
            }
        }
        //下一次执行人为黑棋
        nextBlack = true;
        BlackCount = 0;
        WhiteCount = 0;
    }

    /**
     * 绘制棋盘
     */
    public void ShowGoBangCheckerBoard() {
        for (int i = 0; i < 17; i++) {
            for (int j = 0; j < 17; j++) {
                System.out.print(String.format("%-4s", GoBangCheckerBoard[i][j]));
            }
            System.out.print("\n");
        }
    }

    /**
     * 填充棋子
     *
     * @param x
     * @param y
     * @return
     */
    public boolean InputPiece(int x, int y) {
        //先判断范围
        if (x <= 0 || x > 16)
            System.out.println("输入的横坐标范围错误！");
        else if (y <= 0 || y > 16)
            System.out.println("输入的纵坐标范围错误！");
        else {
            //判断位置是否已经有棋子
            if (GoBangCheckerBoard[x][y] == "+") {
                //填充对应棋子
                if (nextBlack) {
                    ++BlackCount;
                    GoBangCheckerBoard[x][y] = BlackChess;
                } else {
                    ++WhiteCount;
                    GoBangCheckerBoard[x][y] = WhiteChess;
                }
                //输出下完的棋盘
                ShowGoBangCheckerBoard();
                return true;
            } else {
                System.out.println("棋盘上已有棋子，重新输入：");
            }
        }
        return false;
    }

    /**
     * 下一步
     */
    public void NextSept() {
        nextBlack = !nextBlack;
    }

    /**
     * 查找是否有胜利者
     *
     * @param x
     * @param y
     * @return
     */
    public WinnerEnum SearchWinner(int x, int y) {
        String piece = nextBlack ? BlackChess : WhiteChess;
        //黑棋没有到5步，无需判断后续的情况
        if (BlackCount < 5)
            return null;
        //判断，如果有五连，则输出胜利者
        if (WinUpDown(x, y, piece) || WinLeftRigth(x, y, piece) || WinLeftSlash(x, y, piece) || WinRightSlash(x, y, piece)) {
            return nextBlack ? WinnerEnum.BlackWinner : WinnerEnum.WhiteWinner;
        }
        //如果棋盘输出满，则平局
        if (BlackCount + WhiteCount == TotalCount)
            return WinnerEnum.DrawnGame;
        return null;
    }

    /**
     * 判断上下是否有五连
     *
     * @param x
     * @param y
     * @return
     */
    public Boolean WinUpDown(int x, int y, String piece) {
        int len = 1;
        //判断上
        for (int i = 1; y - i > 0; i++) {
            if (GoBangCheckerBoard[x][y - i] == piece)
                ++len;
            else
                break;
        }

        //判断下
        for (int i = 1; y + i <= 16; i++) {
            if (GoBangCheckerBoard[x][y + i] == piece)
                ++len;
            else
                break;
        }
        return len >= 5 ? true : false;
    }

    /**
     * 判断左右是否有五连
     *
     * @param x
     * @param y
     * @return
     */
    public Boolean WinLeftRigth(int x, int y, String piece) {
        int len = 1;
        //判断左
        for (int i = 1; x - i > 0; i++) {
            if (GoBangCheckerBoard[x - i][y] == piece)
                ++len;
            else
                break;
        }
        //判断右
        for (int i = 1; x + i <= 16; i++) {
            if (GoBangCheckerBoard[x + i][y] == piece)
                ++len;
            else
                break;
        }
        return len >= 5 ? true : false;
    }

    /**
     * 判断左斜线" \ " 是否有五连
     *
     * @param x
     * @param y
     * @return
     */
    public Boolean WinLeftSlash(int x, int y, String piece) {
        int len = 1;
        //判断左上
        for (int i = 1; x - i > 0 && y - i > 0; i++) {
            if (GoBangCheckerBoard[x - i][y - i] == piece)
                ++len;
            else
                break;
        }

        //判断右下
        for (int i = 1; x + i <= 16 && y + i <= 16; i++) {
            if (GoBangCheckerBoard[x + i][y + i] == piece)
                ++len;
            else
                break;
        }
        return len >= 5 ? true : false;
    }

    /**
     * 判断右斜线" / " 是否有五连
     *
     * @param x
     * @param y
     * @return
     */
    public Boolean WinRightSlash(int x, int y, String piece) {
        int len = 1;
        //判断右上
        for (int i = 1; x + i <= 16 && y - i > 0; i++) {
            if (GoBangCheckerBoard[x + i][y + i] == piece)
                ++len;
            else
                break;
        }

        //判断左上
        for (int i = 1; x - i > 0 && y + i <= 16; i++) {
            if (GoBangCheckerBoard[x - i][y - i] == piece)
                ++len;
            else
                break;
        }


        return len >= 5 ? true : false;
    }


    /**
     * 自定义成员方法实现特征的获取和修改
     *
     * @return
     */
    public boolean isNextBlack() {
        return nextBlack;
    }

}
